package cn.com.ejiakanghu.web;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.com.ejiakanghu.annotation.LoginUser;
import cn.com.ejiakanghu.core.utils.RespUtil;
import cn.com.ejiakanghu.core.vo.BaseResult;
import cn.com.ejiakanghu.dto.LoginInfo;
import cn.com.ejiakanghu.dto.UserInfo;
import cn.com.ejiakanghu.dto.UserRoleData;
import cn.com.ejiakanghu.service.CaptchaCodeManager;
import cn.com.ejiakanghu.service.UserManager;
import cn.com.ejiakanghu.service.UserTokenManager;
import cn.com.ejiakanghu.service.WxOrderService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.util.*;
import org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder;
import org.linlinjava.litemall.db.dao.AgedmallVipLevelMapper;
import org.linlinjava.litemall.db.domain.AgedmallAgent;
import org.linlinjava.litemall.db.domain.AgedmallVipLevel;
import org.linlinjava.litemall.db.domain.LitemallUser;
import org.linlinjava.litemall.db.service.AgedmallAgentService;
import org.linlinjava.litemall.db.service.AgedmallUserInfoService;
import org.linlinjava.litemall.db.service.CouponAssignService;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.db.util.EnumUserRegisterSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.com.ejiakanghu.core.utils.WxResponseCode.*;
import static org.linlinjava.litemall.db.util.DateUtil.DATE_TIME_FORMATTER;


/**
 * @author houzb
 * @Description
 * @create 2021-04-03 22:50
 */
@RestController
@RequestMapping("/common/auth")
public class CommonAuthController {

    @Autowired
    private LitemallUserService userService;
    @Autowired
    private NotifyService notifyService;
    @Autowired
    private CouponAssignService couponAssignService;
    @Autowired
    private WxMaService wxService;
    @Autowired
    private AgedmallUserInfoService agedmallUserInfoService;
    @Autowired
    private AgedmallAgentService agedmallAgentService;
    @Autowired
    private UserManager userManager;
    @Resource
    private AgedmallVipLevelMapper agedmallVipLevelMapper;

    /**
     * @api {post} /common/auth/loginCaptcha 发送手机号注册登录验证码
     * @apiParam {String} phone 用户手机号
     * @apiParam {String} type 获取验证码的类型 例如:LOGIN
     * @apiParam {String} channel 发送验证码的渠道 例如:MSG 短信，VOICE 语音
     * @apiGroup 鉴权服务
     * @apiVersion 0.1.0
     * @apiDescription 获取手机号的登录验证码
     * @apiSuccess {Object} Object 删除结果
     * @apiSuccess {int} code 请求状态码，0表示成功,其它参考状态码文档
     * @apiSuccess {String} message 结果消息说明
     * @apiSuccess {boolean} success 请求是否成功
     * @apiSuccess {Object} data 请求响应的数据
     * @apiSuccessExample {json} Success-Response:
     * {
     * "code": "请求状态码，0表示成功，其它参考状态码文档",
     * "success": "请求是否成功",
     * "timestamp": "服务器当前时间戳10位精确到秒",
     * "message": "请求成功/失败说明",
     * "data": "请求响应数据，对象或数组"
     * }
     */
    @PostMapping("/loginCaptcha")
    public BaseResult registerCaptcha(String phone, String type, String channel) {
        String phoneNumber = phone;
        if (StringUtils.isEmpty(phoneNumber)) {
            return RespUtil.badArgument();
        }
        if (!RegexUtil.isMobileSimple(phoneNumber)) {
            return RespUtil.badArgumentValue();
        }

        if (!notifyService.isSmsEnable()) {
            return RespUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "小程序后台验证码服务不支持");
        }
        String code = CharUtil.getRandomNum(6);
        long timeout = NotifyService.CAPTCHATIMEOUT;
        boolean successful = CaptchaCodeManager.addToCache(phoneNumber, code, timeout);
        if (!successful) {
            return RespUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时" + timeout + "分钟，不能发送");
        }
        notifyService.notifySmsTemplate(phoneNumber, NotifyType.CAPTCHA, new String[]{code, timeout+""});
        return RespUtil.success();
    }

    /**
     * @api {post} /common/auth/captcha 请求验证码
     * @apiParam {String} mobile 手机号
     * @apiParam {String} type 验证码类型
     * @apiGroup 鉴权服务
     * @apiVersion 0.1.0
     * @apiDescription 获取手机号的登录验证码
     * @apiSuccess {Object} Object
     * @apiSuccessExample {json} Success-Response:
     * { "msg": "成功", "code":0, "data": {} }
     */
    @PostMapping("captcha")
    public Object captcha(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        String phoneNumber = JacksonUtil.parseString(body, "mobile");
        String captchaType = JacksonUtil.parseString(body, "type");
        if (StringUtils.isEmpty(phoneNumber)) {
            return ResponseUtil.badArgument();
        }
        if (!RegexUtil.isMobileSimple(phoneNumber)) {
            return ResponseUtil.badArgumentValue();
        }
        if (StringUtils.isEmpty(captchaType)) {
            return ResponseUtil.badArgument();
        }

        if (!notifyService.isSmsEnable()) {
            return ResponseUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "小程序后台验证码服务不支持");
        }
        String code = CharUtil.getRandomNum(6);
        long timeout = NotifyService.CAPTCHATIMEOUT;
        boolean successful = CaptchaCodeManager.addToCache(phoneNumber, code, timeout);
        if (!successful) {
            return ResponseUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时" + timeout + "分钟，不能发送");
        }
        notifyService.notifySmsTemplate(phoneNumber, NotifyType.CAPTCHA, new String[]{code, timeout+""});
        return ResponseUtil.ok();
    }

    /**
     * @api {post} /common/auth/login 手机号验证码注册登录
     * @apiParam {String} mobile 手机号吗
     * @apiParam {String} captcha 手机号注册登录验证码
     * @apiParam {String} type 客户端类型
     * @apiParam {String} code 对应小程序平台授权登录的到的code
     * @apiParam {String} nickname 对应小程序平台用户昵称
     * @apiParam {String} avatar 对应小程序平台用户头像图片URL
     * @apiGroup 鉴权服务
     * @apiVersion 0.1.0
     * @apiDescription 手机号验证码注册登录
     * @apiSuccess {int} code 请求状态码，0表示成功,其它参考状态码文档
     * @apiSuccess {String} message 结果消息说明
     * @apiSuccess {boolean} success 请求是否成功
     * @apiSuccess {Object} data 请求响应的数据
     * @apiSuccessExample {json} Success-Response:
     * {
     * "code": "请求状态码，0表示成功，其它参考状态码文档",
     * "success": "请求是否成功",
     * "timestamp": "服务器当前时间戳10位精确到秒",
     * "message": "请求成功/失败说明",
     * "data": "请求响应数据，对象或数组"
     * }
     */
    @PostMapping("login")
    public BaseResult register(LoginInfo loginInfo, HttpServletRequest request) {
        String password = RandomStringUtils.randomAlphanumeric(16);
        String mobile = loginInfo.getMobile();
        String code = loginInfo.getCaptcha();
        // 如果是小程序注册，则必须非空
        // 其他情况，可以为空
        String wxCode = "";
        String aliCode = "";
        String createSource = "";
        String type = loginInfo.getType();
        if (LoginInfo.CTYPE_WEIXIN.equals(type)) {
            wxCode = loginInfo.getCode();
            createSource = EnumUserRegisterSource.WXMINI.getSource();
        } else if (LoginInfo.CTYPE_ALI.equals(type)) {
            aliCode = loginInfo.getCode();
            createSource = EnumUserRegisterSource.ALIMINI.getSource();
        }

        if (StringUtils.isEmpty(password) || StringUtils.isEmpty(mobile)
                || StringUtils.isEmpty(code)) {
            return RespUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        //TODO 为了测试写死验证码，后续需要改回来
//        cacheCode="123456";
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return RespUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        }

        Map<Object, Object> result = new HashMap<Object, Object>();
        List<LitemallUser> userList = userService.queryByMobile(mobile);
        if (userList.size() > 0) {
            LitemallUser user = userList.get(0);
            user.setAvatar(loginInfo.getAvatar());
            user.setNickname(loginInfo.getNickname());
            userService.updateById(user);

            UserInfo userInfo = new UserInfo();
            userInfo.setAvatarUrl(user.getAvatar());
            userInfo.setNickName(user.getNickname());
            userInfo.setGender(user.getGender());
            userInfo.setUid(user.getId());
            userInfo.setPhone(user.getMobile());
            userInfo.setSource(user.getCreateSource());
            userInfo.setCreated(user.getAddTime().format(DATE_TIME_FORMATTER));
            AgedmallVipLevel vipLevel = agedmallVipLevelMapper.selectByPrimaryKey(user.getUserLevel().intValue());
            userInfo.setVipLevel(vipLevel!=null?vipLevel.getVipLevel():0);

            List<AgedmallAgent> agentList = agedmallAgentService.getByUid(user.getId());
            String roles = agentList.stream().map(p -> p.getType()+"").sorted().collect(Collectors.joining(","));
            List<String> deliveryRoles = agedmallAgentService.getDeliveryRoles(user.getId());
            String[] roleArrays=roles.split(",");
            deliveryRoles.addAll(Arrays.asList(roleArrays));
            userInfo.setRoles(org.apache.commons.lang3.StringUtils.join(deliveryRoles,","));
            String token = UserTokenManager.generateToken(user.getId());
            result.put("token", token);
            result.put("userInfo", userInfo);
            return RespUtil.success(result);
        }
        if (!RegexUtil.isMobileSimple(mobile)) {
            return RespUtil.fail(AUTH_INVALID_MOBILE, "手机号格式不正确");
        }

        String openId = "";
        // 非空，则是小程序注册
        // 继续验证openid
        if (!StringUtils.isEmpty(wxCode)) {
            try {
                WxMaJscode2SessionResult wxMaJscode2SessionResult = wxService.getUserService().getSessionInfo(wxCode);
                openId = wxMaJscode2SessionResult.getOpenid();
            } catch (Exception e) {
                e.printStackTrace();
                return RespUtil.fail(AUTH_OPENID_UNACCESS, "openid 获取失败");
            }
            userList = userService.queryByOpenid(openId);
            if (userList.size() > 1) {
                return RespUtil.serious();
            }
            if (userList.size() == 1) {
                LitemallUser checkUser = userList.get(0);
                String checkUsername = checkUser.getUsername();
                String checkPassword = checkUser.getPassword();
                if (!checkUsername.equals(openId) || !checkPassword.equals(openId)) {
                    return RespUtil.fail(AUTH_OPENID_BINDED, "openid已绑定账号");
                }
            }
        }

        LitemallUser user = null;
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user = new LitemallUser();
        user.setUsername(mobile);
        user.setPassword(encodedPassword);
        user.setMobile(mobile);
        user.setWeixinOpenid(openId);
        user.setAvatar(loginInfo.getAvatar());
        user.setNickname(loginInfo.getNickname());
        user.setGender((byte) 0);
        user.setUserLevel((byte) 0);
        user.setStatus((byte) 0);
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.getIpAddr(request));
        user.setCreateSource(createSource);
        userService.add(user);
        agedmallUserInfoService.add(user.getId());


        // 给新用户发送注册优惠券
        couponAssignService.assignForRegister(user.getId());

        // userInfo
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName(user.getNickname());
        userInfo.setAvatarUrl(user.getAvatar());
        userInfo.setGender(user.getGender());
        userInfo.setUid(user.getId());
        userInfo.setPhone(user.getMobile());
        userInfo.setSource(user.getCreateSource());
        userInfo.setCreated(user.getAddTime().format(DATE_TIME_FORMATTER));

        UserRoleData roleData = userManager.getUserRoles(user.getId());
        String rolesStr = roleData.getRoles();
        userInfo.setRoles(rolesStr);

        // token
        String token = UserTokenManager.generateToken(user.getId());

        result.put("token", token);
        result.put("userInfo", userInfo);
        return RespUtil.success(result);
    }

    /**
     * @api {post} /common/auth/resetPhone 账号手机号码重置
     * @apiParam {String}  mobile 手机号
     * @apiParam {String}  code 手机短信码
     * @apiGroup 鉴权服务
     * @apiVersion 0.1.0
     * @apiDescription 绑定新的手机号
     * @apiSuccess {Object} Object
     * @apiSuccessExample {json} Success-Response:
     * { "msg": "成功", "code":0, "data": {} }
     */
    @PostMapping("resetPhone")
    public Object resetPhone(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        String password = JacksonUtil.parseString(body, "password");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");

        if (mobile == null || code == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        }

        List<LitemallUser> userList = userService.queryByMobile(mobile);
        LitemallUser user = null;
        if (userList.size() > 1) {

            return ResponseUtil.fail(AUTH_MOBILE_REGISTERED, "手机号已注册");
        }
        user = userService.findById(userId);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }

        user.setMobile(mobile);
        if (userService.updateById(user) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * @api {post} /common/auth/info 用户信息
     * @apiGroup 鉴权服务
     * @apiVersion 0.1.0
     * @apiDescription 获取用户的账号信息
     * @apiSuccess {Object} Object
     * @apiSuccessExample {json} Success-Response:
     * { "msg": "成功", "code":0, "data": {} }
     */
    @GetMapping("info")
    public BaseResult info(@LoginUser Integer userId) {
        if (userId == null) {
            return RespUtil.unlogin();
        }

        LitemallUser user = userService.findById(userId);
        Map<Object, Object> data = new HashMap<Object, Object>();
        data.put("nickName", user.getNickname());
        data.put("avatar", user.getAvatar());
        data.put("gender", user.getGender());
        data.put("mobile", user.getMobile());

        return RespUtil.success(data);
    }

    @PostMapping("checkSubscribeOfficial")
    public BaseResult checkSubscribeOfficial(@RequestParam String loginCode) {
        // todo sunj 是否关注公众号先默认false
        Map<Object, Object> data = new HashMap<Object, Object>();
        data.put("subscribe", false);

        return RespUtil.success(data);
    }

    @PostMapping("init")
    public BaseResult init(@RequestParam String phoneBrand,
                           @RequestParam String phoneModel,
                           @RequestParam String sysPlatform,
                           @RequestParam String sysVersion,
                           @RequestParam String appVersion,
                           @RequestParam String sdkVersion) {
        // todo sunj 数据库没有配置，先提供接口
        Map<Object, Object> data = new HashMap<Object, Object>();
        data.put("assetsRootUrl", "https://lbb.ejiakanghu.cn/weilao");
        data.put("servicePhone", "4006710500");
        data.put("useHelpUrl", "https://lbb.ejiakanghu.cn/weilao");
        data.put("onlineServiceUrl", "https://lbb.ejiakanghu.cn/weilao");
        data.put("readmeServiceUrl", "https://lbb.ejiakanghu.cn/weilao");
        data.put("sendCaptchaTime", 60);
        Map<Object, Object> subscribeOfficial = new HashMap<Object, Object>();
        subscribeOfficial.put("isShow", "0");
        subscribeOfficial.put("logo", "https://litemall-admin-001.oss-cn-hangzhou.aliyuncs.com/imageb1-1452910101336821760.jpg?Expires=4788835736&OSSAccessKeyId=LTAI5tKdb79Meq5HqDAupYVB&Signature=WCLjT75fO2U9GbougTr%2BOBeSCpU%3D");
        subscribeOfficial.put("title", "引导关注公众号的标题");
        subscribeOfficial.put("desc", "引导关注公众号的描述");
        subscribeOfficial.put("pageUrl", "https://lbb.ejiakanghu.cn/weilao");
        data.put("subscribeOfficial", subscribeOfficial);

        return RespUtil.success(data);
    }
}
